//===============================================================================
// Microsoft patterns & practices Enterprise Library Contribution
// Policy Injection Application Block
//===============================================================================

namespace EntLibContrib.PolicyInjection.CallHandlers
{
	/// <summary>
	/// A generic way to treat groups of objects as a key.
	/// </summary>
	public class Key
	{
		#region Fields
		private EqualityType type;
		private object[] items;
		#endregion

		#region Construction
		/// <summary>
		/// Initializes a new instance of the <see cref="Key"/> class.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="items">The items.</param>
		public Key(EqualityType type, params object[] items)
		{
			this.type = type;
			this.items = items;
		}
		#endregion

		#region Public Methods
		/// <summary>
		/// Serves as a hash function for a particular type.
		/// </summary>
		/// <returns>
		/// A hash code for the current <see cref="T:System.Object"/>.
		/// </returns>
		public override int GetHashCode()
		{
			int hashCode = 0;

			foreach (object item in items)
			{
				if (item != null)
				{
					hashCode ^= item.GetHashCode();
				}
			}

			return hashCode;
		}

		/// <summary>
		/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
		/// </summary>
		/// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
		/// <returns>
		/// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
		/// </returns>
		/// <exception cref="T:System.NullReferenceException">
		/// The <paramref name="obj"/> parameter is null.
		/// </exception>
		public override bool Equals(object obj)
		{
			Key other = obj as Key;

			if (other == null)
			{
				return false;
			}

			if (items.Length != other.items.Length)
			{
				return false;
			}

			for (int i = 0; i < items.Length; ++i)
			{
				if (!AreEqual(items[i], other.items[i]))
				{
					return false;
				}
			}

			return true;
		}
		#endregion

		#region Protected Methods
		/// <summary>
		/// Are the objects x and y equal?
		/// </summary>
		/// <param name="compareValue1">The first value.</param>
		/// <param name="compareValue2">The second value.</param>
		/// <returns></returns>
		protected virtual bool AreEqual(object compareValue1, object compareValue2)
		{
			if (type == EqualityType.Equals)
			{
				return Equals(compareValue1, compareValue2);
			}
			else
			{
				return ReferenceEquals(compareValue1, compareValue2);
			}
		}
		#endregion
	}
}
